package me.stone.stanimeclient.core.ui.player

import android.content.Context
import android.media.AudioManager
import android.net.Uri
import android.view.SurfaceView
import android.view.View
import android.view.ViewGroup.LayoutParams
import android.view.WindowManager
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.media3.common.AudioAttributes
import androidx.media3.common.C
import androidx.media3.common.MediaItem
import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.DefaultRenderersFactory
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.session.MediaSession
import androidx.media3.ui.AspectRatioFrameLayout
import androidx.media3.ui.PlayerView
import io.github.anilbeesetti.nextlib.media3ext.ffdecoder.NextRenderersFactory
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import me.stone.stanimeclient.core.common.extensions.toggleSystemBars
import me.stone.stanimeclient.core.model.FanEpisodeItem
import me.stone.stanimeclient.core.ui.databinding.AgeExoPlayerPanelBinding
import me.stone.stanimeclient.core.ui.player.AgeFanVideoSniffer.AgeFanVideoGetListener
import timber.log.Timber

@UnstableApi
open class AgeExoPlayerHelper private constructor(
    private val panelView: View,
    private val activity: AppCompatActivity
) : DefaultPlayerListener(), AgeFanVideoGetListener {

    companion object {
        @JvmStatic
        fun bind(binding: AgeExoPlayerPanelBinding, activity: AppCompatActivity) =
            AgeExoPlayerHelper(binding.root, activity)
    }

    val volumeManager: VolumeManager by lazy {
        VolumeManager(activity.getSystemService(Context.AUDIO_SERVICE) as AudioManager)
    }

    val brightnessManager: BrightnessManager by lazy {
        BrightnessManager(activity)
    }

    val uiBinding: AgeExoPlayerUIBinding by lazy {
        AgeExoPlayerUIBinding.bind(panelView, activity.lifecycleScope).apply {
            AgeExoPlayerGestureHelper.setupGesture(
                this, volumeManager, brightnessManager
            )
        }
    }

    private val applicationContext: Context
        get() = activity.applicationContext

    private val playerView: PlayerView
        get() = uiBinding.playerView

    private val ratioFrameLayout: AspectRatioFrameLayout
        get() = uiBinding.aspectRatioFrameLayout

    private val coroutineScope: CoroutineScope
        get() = activity.lifecycleScope

    private val actionFlow: SharedFlow<AgeExoPlayerUIBinding.Action>
        get() = uiBinding.actionFlow

    private val isFullscreen: Boolean
        get() = uiBinding.isFullscreen

    private val isLocked: Boolean
        get() = uiBinding.isLockState


    private val mCloseDrawer = MutableSharedFlow<Unit>()
    val closeDrawer: SharedFlow<Unit> = mCloseDrawer

    private var isMenuOpened = false

    fun showDrawerMenu() {
        isMenuOpened = true
    }

    fun closeDrawMenu() {
        isMenuOpened = false
        coroutineScope.launch { mCloseDrawer.emit(Unit) }
    }

//    private fun alertPermissionDialog(helper: NetworkStateHelper) {
//        MaterialAlertDialogBuilder(activity)
//            .setTitle("当前网络状态可能获取的不是很准确，是否允许APP获取准确的网络状态？")
//            .setPositiveButton("允许") { dialog, _ ->
//                dialog.dismiss()
//                uiBinding.backFullscreenUI()
//                uiBinding.playerView.post {
//                    helper.requestPermissionsAndTry()
//                }
//            }
//            .setNegativeButton("不要") { dialog, _ ->
//                dialog.dismiss()
//            }
//            .setCancelable(true)
//            .create().show()
//    }

//    fun bindNetStateHelper(helper: NetworkStateHelper) = coroutineScope.launch {
//        launch {
//            helper.networkModeFlow.collectLatest {
//                if (!uiBinding.isFullscreen) return@collectLatest
//                uiBinding.updateNetState(it)
//            }
//        }
//        launch {
//            uiBinding.actionFlow.combine(helper.grantPermission) { action, permission ->
//                if (permission || action != AgeExoPlayerUIBinding.Action.Network) return@combine
//                alertPermissionDialog(helper)
//            }.collect()
//        }
//    }

//    fun bindBatteryHelper(helper: BatteryStateHelper) = coroutineScope.launch {
//        launch {
//            uiBinding.fullscreenFlow.collectLatest {
//                helper.updateEnableLoopRequest(it)
//            }
//        }
//        launch {
//            helper.battery.collectLatest {
//                uiBinding.updateBatteryState(it)
//            }
//        }
//        helper.request()
//        helper.updateEnableLoopRequest(false)
//    }

    // ***************************************************************************
    // Play Video

    private val sniffer: AgeFanVideoSniffer by lazy {
        AgeFanVideoSniffer.create(activity, this)
    }

    fun playWithEpisodeItem(episodeItem: FanEpisodeItem) {
        uiBinding.updateTitle(episodeItem.episodeName)
        sniffer.sniffing(episodeItem.fullVideoUrl)
    }

    fun updatePlaySpeed(speed: Float) {
        exoPlayer.setPlaybackSpeed(speed)
    }

    private lateinit var exoPlayer: ExoPlayer
    private var mediaSession: MediaSession? = null
    private val surfaceView: SurfaceView
        get() = SurfaceView(activity).apply {
            layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
        }

    // 播放器焦点：播放时暂停其他播放器播放
    var requireAudioFocus: Boolean = true
    // 当耳机丢失连接时自动暂停播放
    var pauseOnHeadsetDisconnect: Boolean = true

    // setExtensionRendererMode: 解码器选择
    // 仅用设备 EXTENSION_RENDERER_MODE_OFF
    // 设备优先 EXTENSION_RENDERER_MODE_ON
    // 应用优先 EXTENSION_RENDERER_MODE_PREFER
    private fun createRenderersFactory() = NextRenderersFactory(applicationContext)
        .setEnableDecoderFallback(true)
        .setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON)

    private fun getAudioAttributes(): AudioAttributes {
        return AudioAttributes.Builder()
            .setUsage(C.USAGE_MEDIA)
            .setContentType(C.AUDIO_CONTENT_TYPE_MOVIE)
            .build()
    }

    private fun createPlayer() {
        val renderersFactory = createRenderersFactory()
        exoPlayer = ExoPlayer.Builder(applicationContext)
            .setRenderersFactory(renderersFactory)
            .setAudioAttributes(getAudioAttributes(), requireAudioFocus)
            .setHandleAudioBecomingNoisy(pauseOnHeadsetDisconnect)
            .build()
        try {
            if (exoPlayer.canAdvertiseSession()) {
                mediaSession = MediaSession.Builder(activity, exoPlayer).build()
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        exoPlayer.addListener(this)
        uiBinding.playerView.apply {
            player = exoPlayer
            setControllerVisibilityListener(PlayerView.ControllerVisibilityListener { visibility ->
                if (isFullscreen) {
                    activity.toggleSystemBars(visibility == View.VISIBLE)
                }
                if (visibility == View.VISIBLE) {
                    uiBinding.hideVolumeInfo(0)
                    uiBinding.hideBrightnessInfo(0)
                    uiBinding.hideSettingInfo(0)
                }
            })
        }
    }

    private fun releasePlayer() {
        exoPlayer.release()
        mediaSession?.release()
        mediaSession = null
    }

    fun initializePlayer() {
        registerExoPlayerObserve()
    }

    init {
        createPlayer()
    }

    private fun registerExoPlayerObserve() {
        activity.lifecycle.addObserver(object : DefaultLifecycleObserver {
            override fun onResume(owner: LifecycleOwner) {
                Timber.d("onResume ...")
                if (exoPlayer.playbackState == Player.STATE_READY) {
                    exoPlayer.play()
                }
            }

            override fun onPause(owner: LifecycleOwner) {
                Timber.d("onPause ...")
                if (exoPlayer.isPlaying) {
                    exoPlayer.pause()
                }
            }

            override fun onDestroy(owner: LifecycleOwner) {
                Timber.d("release player ...")
                releasePlayer()
            }
        })
    }

    final override fun onVideoStreamUrlGet(url: String) {
        activity.lifecycleScope.launch(Dispatchers.IO) {
            val uri = Uri.parse(url)
            val mediaItem = MediaItem.Builder()
                .setMediaId(uri.toString())
                .setUri(uri)
                .build()

            withContext(Dispatchers.Main) {
                surfaceView.let { view ->
                    exoPlayer.setVideoSurfaceView(view)
                    ratioFrameLayout.addView(view, 0)
                }
                exoPlayer.playWhenReady = true
                exoPlayer.setMediaItem(mediaItem)
                exoPlayer.prepare()
            }
        }
    }

    override fun onIsPlayingChanged(isPlaying: Boolean) {
        uiBinding.updatePlayOrPauseButtonIcon(isPlaying)
        // 播放视频时保持常量
        if (isPlaying) {
            activity.window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
        } else {
            activity.window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
        }
    }

    private fun togglePlayOrPause() {
        if (exoPlayer.isPlaying) {
            exoPlayer.pause()
        } else {
            exoPlayer.play()
        }
    }

    private fun toggleLockState() {
        if (uiBinding.isLockState) {
            uiBinding.unlockControllers()
        } else {
            uiBinding.lockControllers()
        }
    }

    private val backPressedCallback by lazy {
        object : OnBackPressedCallback(uiBinding.isFullscreen || uiBinding.isLockState || isMenuOpened) {
            override fun handleOnBackPressed() {
                if (isMenuOpened) {
                    closeDrawMenu()
                    return
                }
                if (uiBinding.isLockState) {
                    playerView.showController()
                    return
                }
                if (uiBinding.isFullscreen) {
                    uiBinding.backFullscreenUI()
                    isEnabled = false
                }
            }
        }.apply {
            activity.lifecycleScope.launch {
                uiBinding.fullscreenFlow
                    .combine(uiBinding.lockStateFlow) { isFullscreen, isLocked ->
                        isEnabled = isFullscreen || isLocked || isMenuOpened
                    }.collect()
            }
        }
    }

    private fun doSafeBack() {
        activity.onBackPressedDispatcher.onBackPressed()
    }

    init {
        activity.onBackPressedDispatcher.addCallback(backPressedCallback)
        coroutineScope.launch {
            actionFlow.collectLatest {
                when (it) {
                    AgeExoPlayerUIBinding.Action.Back -> doSafeBack()
                    AgeExoPlayerUIBinding.Action.PlayOrPause -> togglePlayOrPause()
                    AgeExoPlayerUIBinding.Action.Lock -> toggleLockState()
                    AgeExoPlayerUIBinding.Action.Fullscreen -> uiBinding.showFullscreenUI()
                    else -> {}
                }
            }
        }
    }

    override fun onEvents(player: Player, events: Player.Events) { }

}